/**
 * Copyright 2021 xpstem.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.xpstem.lelink.command;

import com.xpstem.lelink.enums.CommandType;
import com.xpstem.lelink.enums.ReplyType;
import com.xpstem.lelink.operation.EV3Operation;
import com.xpstem.lelink.operation.EV3OperationPackage;
import com.xpstem.lelink.operation.ReturnParam;
import com.xpstem.lelink.type.*;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * EV3 direct command
 * @author billy zhang
 */
public class EV3DirectCommand implements EV3Command {

    private EV3Operation[] operationArr;
    private CommandType commandType;
    private ReplyType replyType;

    private List<ReturnParam<? extends EV3Type>> returnParamList = new ArrayList<>();

    public EV3DirectCommand(EV3Operation... operations) {
        this(CommandType.DIRECT_COMMAND_REPLY, operations);
    }

    public EV3DirectCommand(CommandType commandType,
                            EV3Operation... operationArr) {
        this.commandType = commandType;
        this.operationArr = operationArr;
        for (int i=0; i<operationArr.length; i++) {
            List<ReturnParam<? extends EV3Type>> params = operationArr[i].getReturnParamList();
            if (params != null) {
                returnParamList.addAll(params);
            }
        }
    }

    @Override
    public CommandType getType() {
        return commandType;
    }

    @Override
    public EV3CommandPackage getMessage() throws IOException {

        EV3OperationPackage[] packageArr = new EV3OperationPackage[operationArr.length];
        for (int i=0; i<operationArr.length; i++) {
            packageArr[i] = operationArr[i].getPayload();
        }
        return new EV3DirectCommandPackage(commandType, packageArr);

    }

    @Override
    public void response(EV3ReplyPackage replyPackage) throws IOException {
        InputStream inputStream = new ByteArrayInputStream(replyPackage.getRawData());
        //skip counter
        inputStream.skip(2);
        //byte3:
        replyType = ReplyType.ofValue((short)inputStream.read());
        replyPackage.setType( replyType );
        //byte4 - n:
        if (inputStream.available() == 0) {
            return;
        }

        if (returnParamList == null || returnParamList.isEmpty()) {
            return;
        }

        byte[] gv = new byte[inputStream.available()];
        inputStream.read(gv);

        ByteArrayInputStream gvStream = new ByteArrayInputStream(gv);
        for (int i=0; i< returnParamList.size(); i++) {
            ReturnParam param = returnParamList.get(i);
            gvStream.reset();
            param.parse(gvStream, param.getIndex());
        }
    }

    @Override
    public String description() {
        String[] descrArr = new String[operationArr.length];
        for (int i=0; i<operationArr.length; i++) {
            descrArr[i] = operationArr[i].description();
        }
        String opDescr = String.join(",", descrArr);
        return "EV3DirectCommand("+ opDescr +")";
    }

    @Override
    public ReplyType getReplyType() {
        return replyType;
    }
}
